#pragma once
#include <ctime>
#include <string>
#include <sstream>
#include "Lock.hpp"
#include <filesystem> //c++17
#include <fstream>
#include <memory>
#include <unistd.h>

namespace LogModule
{
    using namespace MutexModule;

    const std::string defaultname = "log.txt";
    const std::string defaultload = "./log/";
    std::string GetDate()
    {
        std::stringstream ss;
        std::time_t now = std::time(nullptr);
        std::tm local_time{};
        localtime_r(&now, &local_time); // 线程安全

        ss << "["
           << (local_time.tm_year + 1900) << '-'
           << (local_time.tm_mon + 1) << '-'
           << local_time.tm_mday << ' '
           << local_time.tm_hour << ':'
           << local_time.tm_min << ':'
           << local_time.tm_sec << "]";
        return ss.str();
    }

    enum struct LogLevel
    {
        INFO,
        DEBUG,
        WARNING,
        ERROR,
        FATAL
    };

    std::string GetLevelLine(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::WARNING:
            return "WARMNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return "UNDEF";
        }
    }

    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default; // 为啥显示定义，为啥用default;
        virtual void SyncLog(std::string message) = 0;
    };

    class DisplayLogStrategy : public LogStrategy
    {
    public:
        void SyncLog(const std::string message) override
        {
            _mutex.Lock();
            std::cout << message << std::endl;
            _mutex.Unlock();
        }

        ~DisplayLogStrategy()
        {
        }

    private:
        Mutex _mutex;
    };

    class FileLogStrategy : public LogStrategy
    {
    public:
        FileLogStrategy(std::string filename = defaultname,
                        std::string fileload = defaultload)
            : _fileload(fileload), _filename(filename)
        {
            _mutex.Lock();
            if (std::filesystem::exists(_fileload))
            {
                return;
            }
            try
            {
                std::filesystem::create_directories(_fileload);
            }
            catch (const std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << '\n';
            }
            _mutex.Unlock();
        }

        void SyncLog(const std::string message) override
        {
            _mutex.Lock();
            std::string path = _fileload + _filename;
            std::ofstream out(path.c_str(), std::ios::app); // 追加方式
            if (!out.is_open())
            {
                std::cerr << "[Logger] Failed to open log file: " << path << '\n';
                _mutex.Unlock();
                return;
            }
            out << message << "\n";
            out.close();
            _mutex.Unlock();
        }

        ~FileLogStrategy()
        {
        }

    private:
        std::string _fileload;
        std::string _filename;
        Mutex _mutex;
    };

    // 具体的日志类
    class Logger
    {
    public:
        Logger()
        {
            UseDisplayStrategy();
        }

        void UseDisplayStrategy()
        {
            _logstrategy = std::make_unique<DisplayLogStrategy>();
        }

        void UseFileStrategy()
        {
            _logstrategy = std::make_unique<FileLogStrategy>();
        }

        // 内部类,日志
        class LogMessage
        {
        public:
            LogMessage(LogLevel type, std::string &filename, int line, Logger &logger)
                : _type(type), _curr_time(GetDate()), _pid(getpid()), _filename(filename), _line(line), _logger(logger)
            {
                _loginfo = _curr_time +
                           " [" + GetLevelLine(_type) + "]" +
                           " [" + std::to_string(_pid) + "]" +
                           " [" + _filename + "]" +
                           " [" + std::to_string(line) + "]";
            }

            // 重载支持日志的输入功能
            template <typename T>
            LogMessage &operator<<(const T &info)
            {
                std::stringstream ssbuffer;
                ssbuffer << info;
                _loginfo += ssbuffer.str();
                return *this;
            }

            ~LogMessage()
            {
                if (_logger._logstrategy)
                {
                    _logger._logstrategy->SyncLog(_loginfo);
                }
            }

        private:
            LogLevel _type;         // 日志等级
            std::string _curr_time; // 日志时间
            pid_t _pid;             // 进程pid
            std::string _filename;  // 对应的文件名
            int _line;              // 对应的行号
            Logger &_logger;        // 回指指针
            std::string _loginfo;   // 完整的一条日志
        };

    LogMessage operator()(LogLevel type, std::string filename, int line)
    {
        return LogMessage(type, filename, line, *this);
    }

    private:
        std::unique_ptr<LogStrategy> _logstrategy;
    };

    Logger logger;

#define LOG(type) logger(type, __FILE__, __LINE__)
#define ENABLE_DISPLAY_LOG_STRATEGY() logger.UseDisplayStrategy()
#define ENABLE_FILE_LOG_STRATEGY() logger.UseFileStrategy()
}